package edu.chl.dat076.datesite.ejbs;

import edu.chl.dat076.datesite.entities.Conversation;
import edu.chl.dat076.datesite.entities.Gender;
import edu.chl.dat076.datesite.entities.PartnerCriteria;
import edu.chl.dat076.datesite.entities.SiteUser;
import edu.chl.dat076.datesite.entities.SiteUser_;
import edu.chl.dat076.datesite.entities.UserProperties;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Vector;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

/**
 *
 * @author Christoffer
 * @author Mikey
 */
@Stateless
public class UserEJB implements UserEJBLocal {
	
	@PersistenceContext(unitName = "datesite_pu")
	private EntityManager em;
	
	@Override
	public boolean createUser(SiteUser user) {
		// Kolla så användaren inte finns
		if (isUser(user.getUsername())) {
			return false;
		} else {
			// Skapa/sätt defaultvärden
			if (user.getFriends() == null) {
				user.setFriends(new ArrayList<SiteUser>());
			}
			if (user.getConversations() == null) {
				user.setConversations(new ArrayList<Conversation>());
			}
			if (user.getPartnerCritera() == null) {
				user.setPartnerCritera(new PartnerCriteria());
			}
			if (user.getUserProperties() == null) {
				user.setUserProperties(new UserProperties(new Date(60,01,01), Gender.MALE));
			}
			user.setProfilePic("http://upload.wikimedia.org/wikipedia/commons/7/79/Face-smile.svg");
			user.getUserProperties().setHeight(150);
			user.setVip(false);
			
			em.persist(user);
			
			// Kolla så användaren verkligen blivit registrerad
			return isUser(user.getUsername());
		}
	}
        
    @Override
        public void addFavorite(SiteUser user, SiteUser favorite) {
            user.addFriend(favorite);
            em.merge(user);
        }
    
        

	
	@Override
	public SiteUser getUser(Long id) {
		CriteriaBuilder builder = em.getCriteriaBuilder();
		CriteriaQuery<SiteUser> query = builder.createQuery(SiteUser.class);
		Root<SiteUser> su = query.from(SiteUser.class);
		query.select(su).where(builder.equal(su.get("id"), id));
		TypedQuery<SiteUser> tq = em.createQuery(query);
		
		if (tq.getResultList().isEmpty()) {
			return null;
		} else {
			return tq.getSingleResult();
		}
	}
	
	@Override
	public SiteUser getUser(String username) {
		CriteriaBuilder builder = em.getCriteriaBuilder();
		CriteriaQuery<SiteUser> query = builder.createQuery(SiteUser.class);
		Root<SiteUser> su = query.from(SiteUser.class);
		query.select(su).where(builder.equal(su.get("username"), username));
		TypedQuery<SiteUser> tq = em.createQuery(query);
		
		if (tq.getResultList().isEmpty()) {
			return null;
		} else {
			return tq.getSingleResult();
		}
	}
	
	@Override
	public void editUser(SiteUser user) throws NonexistentEntityException {
           try {
                user = em.merge(user);
           } 
           catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Long id = user.getId();
                    if (getUser(id) == null) {
                        throw new NonexistentEntityException("The user no longer exists");
                    }
                }
            } finally {

           }
	}
	
	@Override
	public boolean deleteUser(Long id) {
		return deleteUser(getUser(id));
	}
	
	@Override
	public boolean deleteUser(String username) {
		return deleteUser(getUser(username));
	}
	
	private boolean deleteUser(SiteUser user) {
		if (user != null) {
			em.remove(user);
			
			// Returnera true om användaren är borta
			return !isUser(user.getId());
		} else {
			return false;
		}
	}
	
	// Kollar användarnamn och lösenord
	@Override
	public boolean okLogin(String username, String password) {
		SiteUser user = getUser(username);
		if (user != null) {
			if (user.getPassword().equals(password)) {
				return true;
			}
		}
		return false;
	}
	
	@Override
	public boolean usernameTaken(String username) {
		return isUser(username);
	}
	
	@Override
	public List<SiteUser> searchUsers(String username, PartnerCriteria pc) {
		CriteriaBuilder builder = em.getCriteriaBuilder();
		CriteriaQuery<SiteUser> query = builder.createQuery(SiteUser.class);
		Root<SiteUser> su = query.from(SiteUser.class);
		Path<UserProperties> up = su.get(SiteUser_.userProperties);
		ParameterExpression<Date> bd = builder.parameter(Date.class);
		
		// Kan det fixas på något snygare sätt? Att sätta till null ger exception
		Predicate p1, p2, p3, p4, p5, p6, p7, p8;
		p1 = p2 = p3 = p4 = p5 = p6 = p7 = p8 = builder.or();

		// Kolla om något speciellt användarnamn angetts
		if (username != null) {
			p1 = builder.like(su.get(SiteUser_.username), "%" + username + "%");
		}
		
		// Kolla vad som angetts i PartnerCriteria-objektet och lägg till
		// sökparametrarna till databasförfrågningen
		if (pc != null) {
			/* Ska kolla ålder, men fick inte till något vettigt sätt att jämnföra
			   datum på.
			 
			if (pc.getPcMinAge() > 0 && pc.getPcMinAge() < 100) {
				p2 = ?
			}
			if (pc.getPcMaxAge() > 0 && pc.getPcMaxAge() < 100) {
				p3 = ?
			}
			*/
			
			if (pc.getPcMinHeight() > 0) {
				p4 = builder.greaterThanOrEqualTo(up.get("height").as(Integer.class), pc.getPcMinHeight());
			}
			if (pc.getPcMaxHeight() > 0) {
				p5 = builder.lessThanOrEqualTo(up.get("height").as(Integer.class), pc.getPcMaxHeight());
			}
			if (!pc.isPcTobaccoUser()) {
				p6 = builder.equal(up.get("tobaccoUser"), false);
			}
			if (!pc.isPcChildren()) {
				p7 = builder.equal(up.get("children"), false);
			}
			if (pc.getPcGender() != null) {
				p8 = builder.equal(up.get("gender").as(Gender.class), pc.getPcGender());
			}
		}

		Predicate andAll = builder.and(p1, p2, p3, p4, p5, p6, p7, p8);
		query.where(andAll);
		query.select(su);
		
		TypedQuery<SiteUser> tq = em.createQuery(query);
		
		return tq.getResultList();
	}

        @Override
        public List<SiteUser> getAllUsers() {
		CriteriaBuilder builder = em.getCriteriaBuilder();
		CriteriaQuery<SiteUser> query = builder.createQuery(SiteUser.class);
		Root<SiteUser> su = query.from(SiteUser.class);
		Query q = em.createQuery(query);
		
		if (q.getResultList().isEmpty()) {
			return null;
		} else {
                    Vector<SiteUser> results = (Vector<SiteUser>) q.getResultList();
                    ArrayList<SiteUser> res = new ArrayList<SiteUser>();
                    res.addAll(results);
                    return res;
		}            
        }

	// Hjälpfunktioner för att kolla som användare finns
	private boolean isUser(String username) {
		if (getUser(username) == null) {
			return false;
		} else {
			return true;
		}
	}
	
	private boolean isUser(Long id) {
		if (getUser(id) == null) {
			return false;
		} else {
			return true;
		}
	}
}
